﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace XMerp
{
    public static class Controls_RawInput
    {
        private const int RIDEV_INPUTSINK = 0x100;
        private const uint RID_INPUT = 0x10000003;
        private const uint RIDI_DEVICENAME = 0x20000007;
        public static void 订阅WM_INPUT信息(IntPtr Handle)
        {
            RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[1];

            rid[0].usUsagePage = 0x01;

            rid[0].usUsage = 0x06;

            rid[0].dwFlags = RIDEV_INPUTSINK;//| RIDEV_NoLegacy;

            rid[0].hwndTarget = Handle;

            RegisterRawInputDevices(rid, (uint)rid.Length, (uint)Marshal.SizeOf(rid[0]));
        }
        public static RawInputData processMessage(this Message message)
        {
            uint dwSize = 0;

            GetRawInputData(message.LParam, RID_INPUT, IntPtr.Zero, ref dwSize, (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER)));

            IntPtr buffer = Marshal.AllocHGlobal((int)dwSize);

            GetRawInputData(message.LParam, RID_INPUT, buffer, ref dwSize, (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER)));

            RAWINPUT raw = (RAWINPUT)Marshal.PtrToStructure(buffer, typeof(RAWINPUT));

            uint size = (uint)Marshal.SizeOf(typeof(RID_DEVICE_INFO));

            GetRawInputDeviceInfo(raw.header.hDevice, RIDI_DEVICENAME, IntPtr.Zero, ref size);
            IntPtr pData = Marshal.AllocHGlobal((int)size);
            GetRawInputDeviceInfo(raw.header.hDevice, RIDI_DEVICENAME, pData, ref size);

            var res = new RawInputData { deviceName = Marshal.PtrToStringAnsi(pData) };
            switch (raw.keyboard.Message)
            {
                case (uint)21:
                    res.message = "Y"; break;

                case (uint)20:
                    res.message = "T"; break;

                case (uint)11:
                    res.message = "0"; break;
               
                case (uint)10:
                    res.message = "9"; break;

                case (uint)9:
                    res.message = "8"; break;

                case (uint)8:
                    res.message = "7"; break;
                   
                case (uint)7:
                    res.message = "6"; break;

                case (uint)6:
                    res.message = "5"; break;

                case (uint)5:
                    res.message = "4"; break; 

                case (uint)4:
                    res.message = "3"; break;

                case (uint)3:
                    res.message = "2"; break;

                case (uint)2:
                    res.message = "1"; break;
                    
                case (uint)28:
                    res.message = "ENTER";break;
            }
            Marshal.FreeHGlobal(buffer);
            Marshal.FreeHGlobal(pData);
            return res;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct RAWINPUTDEVICE
        {
            [MarshalAs(UnmanagedType.U2)]
            public ushort usUsagePage;

            [MarshalAs(UnmanagedType.U2)]
            public ushort usUsage;

            [MarshalAs(UnmanagedType.U4)]
            public int dwFlags;

            public IntPtr hwndTarget;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct RAWINPUTHEADER
        {
            [MarshalAs(UnmanagedType.U4)]
            public int dwType;

            [MarshalAs(UnmanagedType.U4)]
            public int dwSize;

            public IntPtr hDevice;

            [MarshalAs(UnmanagedType.U4)]
            public int wParam;
        }

        [StructLayout(LayoutKind.Explicit)]
        internal struct RAWINPUT
        {
            [FieldOffset(0)]
            public RAWINPUTHEADER header;

            [FieldOffset(16)]
            public RAWMOUSE mouse;

            [FieldOffset(16)]
            public RAWKEYBOARD keyboard;

            [FieldOffset(16)]
            public RAWHID hid;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct RAWKEYBOARD
        {
            [MarshalAs(UnmanagedType.U2)]
            public ushort MakeCode;

            [MarshalAs(UnmanagedType.U2)]
            public ushort Flags;

            [MarshalAs(UnmanagedType.U2)]
            public ushort Reserved;

            [MarshalAs(UnmanagedType.U2)]
            public ushort VKey;

            [MarshalAs(UnmanagedType.U4)]
            public uint Message;

            [MarshalAs(UnmanagedType.U4)]
            public uint ExtraInformation;
        }

        [StructLayout(LayoutKind.Explicit)]
        internal struct RAWMOUSE
        {
            [MarshalAs(UnmanagedType.U2)]
            [FieldOffset(0)]
            public ushort usFlags;

            [MarshalAs(UnmanagedType.U4)]
            [FieldOffset(4)]
            public uint ulButtons;

            [FieldOffset(4)]
            public BUTTONSSTR buttonsStr;

            [MarshalAs(UnmanagedType.U4)]
            [FieldOffset(8)]
            public uint ulRawButtons;

            [FieldOffset(12)]
            public int lLastX;

            [FieldOffset(16)]
            public int lLastY;

            [MarshalAs(UnmanagedType.U4)]
            [FieldOffset(20)]
            public uint ulExtraInformation;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct BUTTONSSTR
        {
            [MarshalAs(UnmanagedType.U2)]
            public ushort usButtonFlags;

            [MarshalAs(UnmanagedType.U2)]
            public ushort usButtonData;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct RAWHID
        {
            [MarshalAs(UnmanagedType.U4)]
            public int dwSizHid;

            [MarshalAs(UnmanagedType.U4)]
            public int dwCount;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct RID_DEVICE_INFO_HID
        {
            [MarshalAs(UnmanagedType.U4)]
            public int dwVendorId;

            [MarshalAs(UnmanagedType.U4)]
            public int dwProductId;

            [MarshalAs(UnmanagedType.U4)]
            public int dwVersionNumber;

            [MarshalAs(UnmanagedType.U2)]
            public ushort usUsagePage;

            [MarshalAs(UnmanagedType.U2)]
            public ushort usUsage;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct RID_DEVICE_INFO_KEYBOARD
        {
            [MarshalAs(UnmanagedType.U4)]
            public int dwType;

            [MarshalAs(UnmanagedType.U4)]
            public int dwSubType;

            [MarshalAs(UnmanagedType.U4)]
            public int dwKeyboardMode;

            [MarshalAs(UnmanagedType.U4)]
            public int dwNumberOfFunctionKeys;

            [MarshalAs(UnmanagedType.U4)]
            public int dwNumberOfIndicators;

            [MarshalAs(UnmanagedType.U4)]
            public int dwNumberOfKeysTotal;
        }

        [StructLayout(LayoutKind.Explicit)]
        internal struct RID_DEVICE_INFO
        {
            [FieldOffset(0)]
            public int cbSize;

            [FieldOffset(4)]
            public int dwType;

            [FieldOffset(8)]
            public RID_DEVICE_INFO_MOUSE mouse;

            [FieldOffset(8)]
            public RID_DEVICE_INFO_KEYBOARD keyboard;

            [FieldOffset(8)]
            public RID_DEVICE_INFO_HID hid;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct RID_DEVICE_INFO_MOUSE
        {
            [MarshalAs(UnmanagedType.U4)]
            public int dwId;

            [MarshalAs(UnmanagedType.U4)]
            public int dwNumberOfButtons;

            [MarshalAs(UnmanagedType.U4)]
            public int dwSampleRate;

            [MarshalAs(UnmanagedType.U4)]
            public int fHasHorizontalWheel;
        }

        [DllImport("User32.dll")]
        extern static uint GetRawInputData(IntPtr hRawInput, uint uiCommand, IntPtr pData, ref uint pcbSize, uint cbSizeHeader);

        [DllImport("User32.dll")]
        extern static bool RegisterRawInputDevices(RAWINPUTDEVICE[] pRawInputDevice, uint uiNumDevices, uint cbSize);

        [DllImport("User32.dll")]
        extern static uint GetRawInputDeviceInfo(IntPtr hDevice, uint uiCommand, IntPtr pData, ref uint pcbSize);
    }
    public class RawInputData
    {
        public string deviceName { get; set; }
        public string message { get; set; }
    }
}
